home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / HippoDraw / hippo / hippoplotX11.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-28  |  27.6 KB  |  1,067 lines

  1. /*                               
  2.  * hippoplotX.c -- Graphics code for producing pure X displays.
  3.  *
  4.  *
  5.  * Author          : Tony Johnson
  6.  * Created On      : 8 Feb 1992
  7.  * Last Modified By: Tony Johnson
  8.  * Last Modified On: 8 Feb 1992
  9.  * Update Count    : 
  10.  * Status          : Revision 1
  11.  *
  12.  * Copyright (C)  1991  The Board of Trustees of The Leland Stanford
  13.  * Junior University.  All Rights Reserved.
  14.  *
  15.  * $Id: hippoplotX11.c,v 1.2 1992/04/28 22:14:44 rensing Rel $
  16.  */ 
  17.  
  18.  
  19. #include "hippoplotX11.h"
  20.  
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <math.h>
  24.  
  25. GLOB_QUAL const char hippoplotX11_c_rcsid[] = 
  26.      "$Id: hippoplotX11.c,v 1.2 1992/04/28 22:14:44 rensing Rel $";
  27.  
  28. GLOB_QUAL const char hippoplotX11_h_rcsid[] = HIPPOPLOTX11_H_RCSID;
  29.  
  30. #define FontName\
  31.   "-Adobe-New Century Schoolbook-Bold-R-Normal--*-*-*-*-*-*-*-*"
  32. #define MAXFONTS 30
  33. #define MAXCACHE 20
  34.  
  35. #define min(A,B) ((A>B) ? B : A)
  36.  
  37. /* These are for passing info from Histo class: */
  38.  
  39. static Display     *h_display;
  40. static Drawable    h_drawable;
  41. static GC          h_gc;
  42. static Font        h_font[MAXFONTS];
  43. static XFontStruct *h_fontStruct;
  44. static int         h_nFonts;
  45. static char        **h_fontNames;
  46. static int         h_depth;
  47. static int         h_color;
  48. static Screen      *h_screen;
  49.  
  50. static init = 0;
  51.  
  52. /* All scaling info: */
  53.  
  54. static struct {
  55.    float x;
  56.    float y;
  57.    int xMarg;
  58.    int yMarg;
  59.    float xOrig;
  60.    float yOrig;
  61. } Scale, Convert;
  62.  
  63. /* The Data-coords limits: */
  64.  
  65. static struct {
  66.    float xmin;
  67.    float xmax;
  68.    float ymin;
  69.    float ymax;
  70. } Limit;
  71.  
  72. static void drawStipple2D_X11(int nXBins,
  73.                   int nYBins,
  74.                   float minBin,
  75.                   float maxBin,
  76.                   float bins[]);
  77. static void ColorError();
  78.  
  79.  
  80. static int XScale(float x)
  81. {
  82.    return (x - Scale.xOrig)*Scale.x + Scale.xMarg;
  83. }
  84. static int YScale(float y)
  85. {
  86.    return Scale.yMarg - (y - Scale.yOrig)*Scale.y;
  87. }
  88. static int XConvert(float x)
  89. {
  90.    return (x - Convert.xOrig)*Convert.x + Convert.xMarg;
  91. }
  92. static int YConvert(float y)
  93. {
  94.    return Convert.yMarg - (y - Convert.yOrig)*Convert.y;
  95. }
  96. void initPlot_X11(Display *disp, Screen *screen, Drawable drawable, GC gc)
  97. {
  98.    h_display   = disp;
  99.    h_drawable  = drawable;
  100.    h_gc        = gc;
  101.    h_screen    = screen;
  102.  
  103.    if (!init)
  104.      {
  105.        int i;
  106.        init = 1;
  107.        h_fontNames = XListFontsWithInfo(disp,FontName,MAXFONTS,
  108.                                         &h_nFonts,&h_fontStruct);
  109.  
  110.        for (i=0; i<h_nFonts; i++) h_font[i] = 0;
  111.  
  112.      }
  113.  
  114.    /* Are we in color? */
  115.  
  116.    h_color = (DefaultVisualOfScreen(h_screen)->class == PseudoColor);
  117. }
  118.  
  119. static void ColorError()
  120. {
  121.    static Reported = 0;
  122.    if (Reported++) return;
  123.   
  124.    printf("\nXHippo: Unable to allocate required colormap entries\n");
  125. }
  126.  
  127. void setHistoCoords_X11(rectangle *draw,
  128.                       rectangle *margin, 
  129.                       rectangle *data)
  130. {
  131.    unsigned int width, height, border;
  132.    int x,y;
  133.    Window root;
  134.     
  135.    /* Get overall width and height from window. */
  136.  
  137.    XGetGeometry(h_display,h_drawable,&root,&x,&y,&width,
  138.         &height,&border,&h_depth);   
  139.  
  140.    /* Remember margin is in points; data is in data coords. */
  141.  
  142.    Convert.x = width/draw->size.width;
  143.    Convert.y = height/draw->size.height;
  144.    Convert.xMarg = 0;
  145.    Convert.yMarg = height;
  146.    Convert.xOrig = draw->origin.x;
  147.    Convert.yOrig = draw->origin.y;
  148.  
  149.    Scale.x = (Convert.x * margin->size.width)/(data->size.width);
  150.    Scale.y = (Convert.y * margin->size.height)/(data->size.height);
  151.    Scale.xMarg = XConvert(margin->origin.x);
  152.    Scale.yMarg = YConvert(margin->origin.y);
  153.    Scale.xOrig = data->origin.x;
  154.    Scale.yOrig = data->origin.y;
  155.    
  156.    Limit.xmin = data->origin.x;
  157.    Limit.xmax = data->size.width + data->origin.x;
  158.    Limit.ymin = data->origin.y;
  159.    Limit.ymax = data->size.height + data->origin.y;
  160.    
  161. #ifdef DEBUG
  162.    printf ("setupX: X scale = %f, Y scale = %f\n", Scale.x, Scale.y);
  163. #endif
  164. }
  165.  
  166. /*  Put the message text at the indicated x-y position (Note, x and y
  167.  *  are in points):
  168.  */
  169.  
  170. void drawText_X11(char *message,
  171.             float x,
  172.              float y,
  173.         float fontHeight,
  174.         float angle,
  175.         char xalign,
  176.         char yalign)
  177. {
  178.    int xx = XConvert(x);
  179.    int yy = YConvert(y);
  180.    int width, dir, ascent, descent;
  181.    int length = strlen(message);
  182.    int i, n, size;
  183.    double sinA = sin(angle), cosA = cos(angle);
  184.  
  185.    
  186.    XCharStruct overall;
  187.  
  188.    /* Decide which font to use */
  189.  
  190.    int fontSize = min(Convert.x , Convert.y) * fontHeight;
  191.    
  192.    size = 0;
  193.    for (i=0; i<h_nFonts; i++)
  194.      {
  195.        int h = h_fontStruct[i].ascent + h_fontStruct[i].descent;
  196.        if (h <= fontSize && h > size) 
  197.          { 
  198.            size = h;
  199.            n = i;
  200.          }
  201.      }
  202.    if (size == 0)
  203.      {
  204.        size = 99999;
  205.        for (i=0; i<h_nFonts; i++)
  206.          {
  207.            int h = h_fontStruct[i].ascent + h_fontStruct[i].descent;
  208.            if (h < size)
  209.              {
  210.                size = h;
  211.                n = i;
  212.              }
  213.          }
  214.      }
  215.  
  216.    if (h_font[n] == 0) 
  217.      {
  218.        h_fontStruct[n] = *XLoadQueryFont(h_display,h_fontNames[n]);
  219.        h_font[n] = h_fontStruct[n].fid;
  220.      }
  221.       
  222. #ifdef DEBUG
  223.    printf("fontHeight,Convert.x,Convert.y,angle,font %f,%f,%f,%f\n%s",
  224.            fontHeight,Convert.x,Convert.y,angle,h_fontNames[n]);
  225. #endif
  226.  
  227.    XSetFont(h_display,h_gc,h_font[n]);
  228.    XTextExtents(&h_fontStruct[n],message,length,&dir,
  229.         &ascent,&descent,&overall);
  230.    width = overall.width;
  231.    ascent = overall.ascent;
  232.    descent = overall.descent;
  233.  
  234.    switch (xalign) 
  235.      {
  236.        case 'C':
  237.        case 'c':
  238.          xx -= cosA*width/2 + sinA*(ascent - descent)/2; 
  239.          break;
  240.        
  241.        case 'R':
  242.        case 'r':
  243.          xx -= cosA*width + sinA*ascent;
  244.          break;
  245.  
  246.        case 'L':
  247.        case 'l':
  248.        default:
  249.          xx += sinA*ascent;
  250.          break;
  251.      }
  252.  
  253.    switch (yalign) 
  254.      {
  255.        case 'C':
  256.        case 'c':
  257.          yy += cosA*(ascent - descent)/2 - sinA*width/2;
  258.          break;
  259.        
  260.        case 'T':
  261.        case 't':
  262.          yy += cosA*ascent - sinA*width;
  263.          break;
  264.  
  265.        case 'B':
  266.        case 'b':
  267.        default:
  268.          yy -= cosA*descent;
  269.          break;
  270.      }
  271.  
  272.    if (angle!=0)
  273. /*
  274.  *  There is no good way to deal with angled text prior to X11R5.
  275.  *  The following is an inelegant work around. This can probably
  276.  *  be done better with X11R5. This code is currently set up to rotate
  277.  *  by a fixed 90 degress (ie angle is ignored).
  278.  */
  279.      {
  280.        int height = ascent + descent;
  281.        int i;
  282.        static struct {
  283.          char   *text;
  284.          Pixmap  map;
  285.          } cache[MAXCACHE];
  286.  
  287.        static int Ncache = 0;
  288.  
  289.        for (i=0; i<Ncache; i++)
  290.          {
  291.            if (strcmp(cache[i].text,message) == 0) break; 
  292.          }
  293.        if (i<Ncache)
  294.          {
  295.            XCopyArea(h_display,cache[i].map,h_drawable,
  296.              h_gc,0,0,height,width,xx,yy);
  297.          }
  298.        else
  299.          {
  300.            int i,j;
  301.            XImage *image, *rimage; 
  302.            XGCValues values;
  303.          
  304.            GC gc_temp = XCreateGC(h_display,h_drawable,0,&values);      
  305.  
  306.            Pixmap New = XCreatePixmap(h_display,h_drawable, 
  307.                                       width,height,h_depth);
  308.            Pixmap Rot = XCreatePixmap(h_display,h_drawable,
  309.                                       height,width,h_depth);
  310.  
  311.            XGetGCValues(h_display,h_gc,GCBackground,&values); 
  312.            values.foreground = values.background;
  313.            XChangeGC(h_display,gc_temp,GCForeground,&values);
  314.            XFillRectangle(h_display,New,gc_temp,0,0,width,height);
  315.            XFreeGC(h_display,gc_temp);
  316.  
  317.            XDrawString(h_display,New,h_gc,0,ascent,message,length);
  318.            image = XGetImage(h_display,New,0,0,width,height,
  319.                  AllPlanes,XYPixmap);
  320.            rimage = XGetImage(h_display,Rot,0,0,height,width,
  321.                   AllPlanes,XYPixmap);
  322.        
  323.            for (i=0; i<width; i++) 
  324.              for (j=0; j<height; j++)
  325.                XPutPixel(rimage,j,width-i-1,XGetPixel(image,i,j));
  326.        
  327.            XPutImage(h_display,Rot,h_gc,rimage,0,0,0,0,height,width);
  328.  
  329.            XCopyArea(h_display,Rot,h_drawable,h_gc,0,0,height,width,xx,yy);
  330.  
  331.            XFreePixmap(h_display,New);
  332.            XDestroyImage(image);
  333.            XDestroyImage(rimage);
  334.  
  335.            if (Ncache == MAXCACHE)
  336.              {
  337.                XFreePixmap(h_display,cache[0].map);
  338.                free(cache[0].text);
  339.                for (i=1; i<MAXCACHE; i++) cache[i-1] = cache[i];   
  340.                Ncache--;
  341.              }
  342.            cache[Ncache].map = Rot;
  343.            cache[Ncache].text = strcpy(malloc(length+1),message);
  344.            Ncache++;
  345.          }
  346.      } 
  347.    else { XDrawString(h_display,h_drawable,h_gc,xx,yy,message,length); }     
  348. }
  349.  
  350.  
  351.  
  352. void drawMag_X11(float x, float y,
  353.          int mag, float fontsize)
  354.  
  355. /* x and y are in device coords (points). */
  356. {
  357.   char buffer[12];
  358.   sprintf(buffer,"%d",mag);
  359.   
  360.   drawText_X11("x10",x,y,fontsize,0,'r','c'); 
  361.   drawText_X11(buffer,x,y,fontsize,0,'l','b');
  362. }
  363.  
  364.  
  365.  
  366. void drawXTicks_X11(float *x,
  367.             int nt,
  368.             float tickwidth,
  369.             int side)
  370. {
  371.    XSegment *segs = (XSegment *) malloc(nt*sizeof(XSegment));
  372.    XSegment *ns = segs;
  373.    int i;
  374.    short y1, y2;
  375.    
  376.    if (side == 0)
  377.      {
  378.        y1 = YScale(Limit.ymin);
  379.        y2 = y1 - Convert.y * tickwidth;
  380.      }
  381.    else
  382.      {
  383.        y1 = YScale(Limit.ymax) + 1;
  384.        y2 = y1 + Convert.y * tickwidth;
  385.      }
  386.  
  387.    for (i = 0; i < nt; i++)
  388.      {
  389.        ns->x1 = XScale(*x++);
  390.        ns->x2 = ns->x1;
  391.        ns->y1 = y1;
  392.        ns->y2 = y2;
  393.        ns++;
  394.      }
  395.    XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);
  396.  
  397.    XDrawSegments(h_display,h_drawable,h_gc,segs,nt);
  398.    free(segs);
  399. }
  400.  
  401. void drawYTicks_X11(float* y,
  402.           int nt,
  403.           float tickwidth,
  404.           int side)
  405. {
  406.    XSegment *segs = (XSegment *) malloc(nt*sizeof(XSegment));
  407.    XSegment *ns = segs;
  408.    int i;
  409.    short x1, x2;
  410.    
  411.    if (side == 0)
  412.      {
  413.        x1 = XScale(Limit.xmin) + 1;
  414.        x2 = x1 + Convert.x * tickwidth;
  415.      }
  416.    else
  417.      {
  418.        x1 = XScale(Limit.xmax);
  419.        x2 = x1 - Convert.x * tickwidth;
  420.      }
  421.  
  422.    for (i = 0; i < nt; i++)
  423.      {
  424.        ns->y1 = YScale(*y++);
  425.        ns->y2 = ns->y1;
  426.        ns->x1 = x1;
  427.        ns->x2 = x2;
  428.        ns++;
  429.      }
  430.    XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);
  431.  
  432.    XDrawSegments(h_display,h_drawable,h_gc,segs,nt);
  433.    free(segs);
  434. }
  435.  
  436. void drawRect_X11(float x, float y,
  437.                  float width, float height)
  438.  
  439. /* all args are in window coords */
  440. {
  441.       XDrawRectangle(h_display, h_drawable, h_gc, XConvert(x), YConvert(y),
  442.                      XConvert(width), XConvert(height));
  443.  
  444. #ifdef DEBUG
  445.    printf("drawRect_X11: rect at (%d, %d) size (%d, %d)\n",
  446.       XConvert(x), YConvert(y), XConvert(width),YConvert(height));
  447. #endif
  448. }
  449.  
  450. void drawFilledRect_X11(float x, float y,
  451.                   float width, float height,
  452.                  float grey)
  453.  
  454. /* all args are in window coords */
  455. {
  456.  
  457.     int xx = XConvert(x);
  458.     int yy = YConvert(y);
  459.     int ww = Convert.x * width;
  460.     int hh = Convert.y * height;
  461.     int color = 256*grey;
  462.  
  463.     XSetForeground(h_display, h_gc, color);
  464.     XFillRectangle(h_display, h_drawable, h_gc, xx, yy, ww, hh); 
  465.     
  466. #ifdef DEBUG
  467.    printf("drawFilledRect_X11: rect at (%d, %d) size (%d, %d) color (%d)\n",
  468.       xx, yy, ww, hh, color);
  469. #endif
  470. }
  471.  
  472. void shade_X11(float xlow, float xhigh,
  473.              float ylow, float yhigh )
  474.  
  475. /* all args are in data coords */
  476. {
  477.  
  478.    int xx = XConvert(xlow);
  479.    int yy = YConvert(yhigh);
  480.    int ww = XConvert(xhigh) - xx;
  481.    int hh = YConvert(ylow) - yy;
  482.  
  483.    Pixmap Stipple;
  484.    static char data[] = {0x02, 0x01};
  485.    
  486.    Stipple = XCreatePixmapFromBitmapData(h_display,h_drawable,data,2,2,0,1,1);
  487.  
  488.    XSetStipple(h_display, h_gc, Stipple);
  489.    XSetFillStyle(h_display,h_gc,FillStippled);   
  490.    XFillRectangle(h_display, h_drawable, h_gc, xx, yy, ww, hh); 
  491.    XSetFillStyle(h_display,h_gc,FillSolid);   
  492.    XFreePixmap(h_display,Stipple);
  493.  
  494. #ifdef DEBUG
  495.    printf("drawFilledRect_X11: rect at (%f, %f) to (%f, %f)\n",
  496.        xlow, ylow, xhigh,yhigh);
  497. #endif
  498. }
  499.  
  500. void drawLine_X11(float *xy, int nxy, linestyle_t ls)
  501. {
  502.    XPoint *points = (XPoint *) malloc(nxy*sizeof(XPoint));
  503.    XPoint *np = points;
  504.    int i;
  505.    for (i = 0; i < nxy; i++)
  506.      {
  507.        np->x = XScale(*xy++);
  508.        np->y = YScale(*xy++);
  509.        np++;
  510.      }
  511.  
  512.    switch (ls)
  513.      {
  514.        char dashlist[4];
  515.   
  516.        case SOLID:
  517.        default:
  518.          XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);
  519.          break;
  520.        case DASH:
  521.          dashlist[0] = 4;
  522.          dashlist[1] = 4;
  523.          XSetDashes(h_display,h_gc,0,dashlist,2);
  524.          XSetLineAttributes(h_display,h_gc,0,LineOnOffDash,CapButt,JoinMiter);
  525.          break;
  526.        case DOT:
  527.          dashlist[0] = 1;
  528.          dashlist[1] = 2;
  529.          XSetDashes(h_display,h_gc,0,dashlist,2);
  530.          XSetLineAttributes(h_display,h_gc,0,LineOnOffDash,CapButt,JoinMiter);
  531.          break;
  532.        case DOTDASH:
  533.          dashlist[0] = 4;
  534.          dashlist[1] = 2;
  535.          dashlist[2] = 1;
  536.          dashlist[3] = 2;
  537.          XSetDashes(h_display,h_gc,0,dashlist,4);
  538.          XSetLineAttributes(h_display,h_gc,0,LineOnOffDash,CapButt,JoinMiter);
  539.          break;
  540.      }
  541.  
  542.    XDrawLines(h_display,h_drawable,h_gc,points,nxy,CoordModeOrigin);
  543.    free(points);
  544. }
  545.  
  546. void drawPoints_X11(float xy[],
  547.           int nxy,
  548.           int symbol,
  549.           float symbolsize)
  550. {
  551.   XRectangle *recs, *r;
  552.   XSegment   *segs, *s;
  553.   int i;
  554.   short simsize = min(Convert.x , Convert.y) * symbolsize/2;
  555.   short width = 4, height = 4, halfwidth=2, halfheight=2;
  556.  
  557.   if (simsize<1) simsize=1;
  558.   halfwidth = simsize;
  559.   halfheight = simsize;
  560.   width = simsize*2;
  561.   height = simsize*2;
  562.   
  563.   switch (symbol) 
  564.     {
  565.       case SQUARE:
  566.       case SOLIDSQUARE:
  567.       default:
  568.  
  569.         recs = (XRectangle *) malloc(nxy*sizeof(XRectangle));
  570.         r = recs;
  571.   
  572.         for (i=0; i<nxy; i++)
  573.           {
  574.             r->x = XScale(*xy++) - halfwidth;
  575.             r->y = YScale(*xy++) - halfheight;
  576.             r->width = width;
  577.             r->height = height;
  578.             r++;
  579.           }
  580.         if (symbol == SOLIDSQUARE) XFillRectangles(h_display,h_drawable,
  581.                            h_gc,recs,nxy);
  582.         else                       XDrawRectangles(h_display,h_drawable,
  583.                            h_gc,recs,nxy);
  584.         free(recs);
  585.         break;
  586.       
  587.       case PLUS:
  588.       case TIMES:
  589.  
  590.         segs = (XSegment *) malloc(nxy*sizeof(XSegment)*2);
  591.         s = segs;
  592.   
  593.         if (symbol==TIMES)
  594.           for (i=0; i<nxy; i++)
  595.             {
  596.               short x = XScale(*xy++);
  597.               short y = YScale(*xy++);
  598.               s->x1 = x-halfwidth;
  599.               s->x2 = x+halfwidth;
  600.               s->y1 = y-halfheight;
  601.               s->y2 = y+halfheight;
  602.               s++;
  603.               s->x1 = x-halfwidth;
  604.               s->x2 = x+halfwidth;
  605.               s->y1 = y+halfheight;
  606.               s->y2 = y-halfheight;
  607.               s++;
  608.             }
  609.         else
  610.           for (i=0; i<nxy; i++)
  611.             {
  612.               short x = XScale(*xy++);
  613.               short y = YScale(*xy++);
  614.               s->x1 = x-halfwidth;
  615.               s->x2 = x+halfwidth;
  616.               s->y1 = y;
  617.               s->y2 = y;
  618.               s++;
  619.               s->x1 = x;
  620.               s->x2 = x;
  621.               s->y1 = y-halfheight;
  622.               s->y2 = y+halfheight;
  623.               s++;
  624.             }
  625.         XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);
  626.         XDrawSegments(h_display,h_drawable,h_gc,segs,nxy*2);
  627.         free(segs);
  628.     }    
  629.  
  630. void drawXError_X11(float xy[],
  631.           float errs[],
  632.           int npts)
  633. {
  634.    XSegment *segs = (XSegment *) malloc(3*npts*sizeof(XSegment));
  635.    XSegment *ns = segs;
  636.    int i;
  637.    short halfwidth = 2;
  638.    
  639.    for (i = 0; i < npts; i++)
  640.      {
  641.        short y, xhi, xlo;
  642.        xy++; /* ignore x value */
  643.        y   = YScale(*xy++);
  644.        xhi = XScale(*errs++);
  645.        xlo = XScale(*errs++);
  646.  
  647.        ns->y1 = y;
  648.        ns->y2 = y;
  649.        ns->x1 = xlo;
  650.        ns->x2 = xhi;
  651.        ns++;
  652.        ns->y1 = y+halfwidth;
  653.        ns->y2 = y-halfwidth;
  654.        ns->x1 = xlo;
  655.        ns->x2 = xlo;
  656.        ns++;
  657.        ns->y1 = y+halfwidth;
  658.        ns->y2 = y-halfwidth;
  659.        ns->x1 = xhi;
  660.        ns->x2 = xhi;
  661.        ns++;
  662.      }
  663.    XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);
  664.  
  665.    XDrawSegments(h_display,h_drawable,h_gc,segs,3*npts);
  666.    free(segs);
  667. }
  668.  
  669.  
  670. void drawYError_X11(float xy[],
  671.           float errs[],
  672.           int npts)
  673. {
  674.    XSegment *segs = (XSegment *) malloc(3*npts*sizeof(XSegment));
  675.    XSegment *ns = segs;
  676.    int i;
  677.    short halfwidth = 2;
  678.    
  679.    for (i = 0; i < npts; i++)
  680.      {
  681.        short x, yhi, ylo;
  682.        x   = XScale(*xy++);
  683.        xy++; /* ignore y value */
  684.        yhi = YScale(*errs++);
  685.        ylo = YScale(*errs++);
  686.  
  687.        ns->x1 = x;
  688.        ns->x2 = x;
  689.        ns->y1 = ylo;
  690.        ns->y2 = yhi;
  691.        ns++;
  692.        ns->x1 = x+halfwidth;
  693.        ns->x2 = x-halfwidth;
  694.        ns->y1 = ylo;
  695.        ns->y2 = ylo;
  696.        ns++;
  697.        ns->x1 = x+halfwidth;
  698.        ns->x2 = x-halfwidth;
  699.        ns->y1 = yhi;
  700.        ns->y2 = yhi;
  701.        ns++;
  702.      }
  703.    XSetLineAttributes(h_display,h_gc,0,LineSolid,CapButt,JoinMiter);
  704.  
  705.    XDrawSegments(h_display,h_drawable,h_gc,segs,3*npts);
  706.    free(segs);
  707. }
  708.  
  709. static void drawStipple2D_X11(int nXBins,
  710.                   int nYBins,
  711.                   float minBin,
  712.                   float maxBin,
  713.                   float bins[])
  714. {
  715.    float xBinWidth = (Limit.xmax - Limit.xmin)/nXBins;
  716.    float yBinWidth = (Limit.ymax - Limit.ymin)/nYBins;
  717.    float x = Limit.xmin;
  718.    float y = Limit.ymin;
  719.  
  720.    float scale = 15.0 / (maxBin - minBin);
  721.    int i,j;
  722.    int xx = XScale(Limit.xmin);
  723.    int yy = YScale(Limit.ymin);
  724.    int ww, hh;
  725.    unsigned long mask = GCForeground | GCBackground | GCFillStyle | GCStipple;
  726.    XGCValues values;
  727.    Pixmap Stipple[16];
  728.    GC temp_gc[16];
  729.  
  730.    static char data[16][4] = {
  731.    {0x0f, 0x0f, 0x0f, 0x0f},
  732.    {0x0f, 0x0e, 0x0f, 0x0f},
  733.    {0x0f, 0x0e, 0x07, 0x0f},
  734.    {0x0d, 0x0e, 0x07, 0x0f},
  735.    {0x0d, 0x0e, 0x07, 0x0b},
  736.    {0x0d, 0x0e, 0x05, 0x0b},
  737.    {0x05, 0x0e, 0x05, 0x0b},
  738.    {0x05, 0x0a, 0x05, 0x0b},
  739.    {0x05, 0x0a, 0x05, 0x0a},
  740.    {0x05, 0x0a, 0x01, 0x0a},
  741.    {0x01, 0x0a, 0x01, 0x0a},
  742.    {0x01, 0x0a, 0x00, 0x0a},
  743.    {0x00, 0x0a, 0x00, 0x0a},
  744.    {0x00, 0x02, 0x00, 0x0a},
  745.    {0x00, 0x02, 0x00, 0x08},
  746.    {0x00, 0x02, 0x00, 0x00}};
  747.  
  748.    for (i=0; i<16; i++)
  749.      Stipple[i] = XCreatePixmapFromBitmapData(h_display,h_drawable,
  750.                           data[i],4,4,0,1,1);
  751.  
  752.    values.foreground = BlackPixelOfScreen(h_screen);
  753.    values.background = WhitePixelOfScreen(h_screen);
  754.    values.fill_style = FillOpaqueStippled;
  755.    
  756.    for (i=0; i<16; i++)
  757.      {
  758.        values.stipple = Stipple[i];
  759.        temp_gc[i] = XCreateGC(h_display,h_drawable,mask,&values);
  760.      }
  761.  
  762.    XFillRectangle(h_display,h_drawable,temp_gc[0],xx,YScale(Limit.ymax),
  763.                   (XScale(Limit.xmax)-xx),(yy-YScale(Limit.ymax)));
  764.  
  765.    for (i=0; i<nXBins; i++)
  766.      {
  767.        x += xBinWidth;
  768.        ww = XScale(x) - xx;
  769.        for (j=0; j<nYBins; j++)
  770.          {
  771.            int ss = scale * (*bins++ - minBin);
  772.            y += yBinWidth;
  773.            hh = yy - YScale(y);
  774.            yy -= hh;
  775.            if (ss!=0) 
  776.              XFillRectangle(h_display,h_drawable,temp_gc[ss],xx,yy,ww,hh);
  777.          }
  778.        xx += ww;
  779.        yy = YScale(Limit.ymin);
  780.        y = Limit.ymin;
  781.      }           
  782.    for (i=0; i<16; i++) 
  783.      { 
  784.        XFreePixmap(h_display,Stipple[i]);
  785.        XFreeGC(h_display,temp_gc[i]);
  786.      }
  787. }
  788.  
  789. void drawColor2D_X11(int nXBins,
  790.            int nYBins,
  791.            float minBin,
  792.            float maxBin,
  793.            float bins[],
  794.                    int fullColor)
  795. {
  796.    float xBinWidth = (Limit.xmax - Limit.xmin)/nXBins;
  797.    float yBinWidth = (Limit.ymax - Limit.ymin)/nYBins;
  798.    float x = Limit.xmin;
  799.    float y = Limit.ymin;
  800.    float scale = 90.0 / (maxBin - minBin);
  801.    int i,j;
  802.    int xx = XScale(Limit.xmin);
  803.    int yy = YScale(Limit.ymin);
  804.    int ww, hh;
  805.  
  806.    static int GotColorMap = 0; 
  807.    static int GotGreyMap  = 0;
  808.    Colormap Map;
  809.    static XColor Color[91];
  810.    static XColor Grey[91];
  811.    XColor *ColorsUsed;
  812.    GC temp_gc;
  813.  
  814.    static struct {
  815.       int red;
  816.       int green;
  817.       int blue;
  818.           }  
  819.                   rainbow[10]    ={{0    ,     0,     0},     /* black   */
  820.                                    {33422, 15728,   553},     /* brown   */
  821.                                    {23912, 14548, 33947},     /* violet  */
  822.                                    {15217, 17377, 41142},     /* indigo  */
  823.                                    {    0,     0, 55049},     /* blue    */
  824.                                    {    0, 50078,   199},     /* green   */
  825.                                    {62193, 60816,     0},     /* yellow  */
  826.                                    {65535, 28180,  1310},     /* orange  */
  827.                                    {65535,  1310,     0},     /* red     */
  828.                                    {65535, 65535, 65535}};    /* white   */   
  829.  
  830.    if (!h_color)
  831.      {
  832.        drawStipple2D_X11(nXBins,nYBins,minBin,maxBin,bins);
  833.        return;
  834.      } 
  835.  
  836.    temp_gc = XCreateGC(h_display,h_drawable,NULL,0);
  837.  
  838.    if (fullColor != 0 && GotColorMap++ == 0)
  839.      {
  840.        int i, j, k=0;
  841.        Map = DefaultColormapOfScreen(h_screen);
  842.          
  843.        for (i=0; i<9; i++)
  844.          {
  845.            for (j=0; j<10; j++)
  846.              {
  847.                Color[k].red   = rainbow[i].red*(10-j)/10   + 
  848.             rainbow[i+1].red*j/10;
  849.                Color[k].blue  = rainbow[i].blue*(10-j)/10  + 
  850.             rainbow[i+1].blue*j/10;
  851.                Color[k].green = rainbow[i].green*(10-j)/10 +
  852.             rainbow[i+1].green*j/10;
  853.                if (!XAllocColor(h_display,Map,&Color[k])) ColorError();
  854.                k++;
  855.              } 
  856.          }
  857.        Color[k].red   = rainbow[9].red;
  858.        Color[k].blue  = rainbow[9].blue;
  859.        Color[k].green = rainbow[9].green;
  860.        if (!XAllocColor(h_display,Map,&Color[k])) ColorError();
  861.      }
  862.    else if (fullColor == 0 && GotGreyMap++ ==0)
  863.      {
  864.        int i; 
  865.        Map = DefaultColormapOfScreen(h_screen);
  866.  
  867.        for (i=0; i<=90; i++)
  868.          {
  869.            int color = 65535-i*65535/90;
  870.            Grey[i].red = color;
  871.            Grey[i].blue = color;
  872.            Grey[i].green = color;
  873.            if (!XAllocColor(h_display,Map,&Grey[i])) ColorError();
  874.          }
  875.      }
  876.  
  877.    if (fullColor == 0) ColorsUsed = Grey;
  878.    else                ColorsUsed = Color; 
  879.  
  880.    XSetForeground(h_display,temp_gc,ColorsUsed[0].pixel);
  881.    XFillRectangle(h_display,h_drawable,temp_gc,xx,YScale(Limit.ymax),
  882.                   (XScale(Limit.xmax)-xx),(yy-YScale(Limit.ymax)));
  883.  
  884.    for (i=0; i<nXBins; i++)
  885.      {
  886.        x += xBinWidth;
  887.        ww = XScale(x) - xx;
  888.        for (j=0; j<nYBins; j++)
  889.          {
  890.            int color = scale * (*bins++ - minBin);
  891.            y += yBinWidth;
  892.            hh = yy - YScale(y);
  893.            yy -= hh;
  894.            if (color==0) continue;
  895.            XSetForeground(h_display,temp_gc,ColorsUsed[color].pixel);
  896.            XFillRectangle(h_display,h_drawable,temp_gc,xx,yy,ww,hh);
  897.          }
  898.        xx += ww;
  899.        yy = YScale(Limit.ymin);
  900.        y = Limit.ymin;
  901.      }           
  902.    XFreeGC(h_display,temp_gc);
  903. }
  904.  
  905. void drawLego2D_X11(int nXBins,
  906.           int nYBins,
  907.           float minBin,
  908.           float maxBin,
  909.           float bins[])
  910. {
  911.    float angle = 45; /* degrees */
  912.    float sin45 = 1./sqrt(2.);
  913.    float cos45 = sin45;
  914.  
  915.    float xBinWidth = (Limit.xmax - Limit.xmin)/nXBins;
  916.    float yBinWidth = cos45*(Limit.ymax - Limit.ymin)/nYBins;
  917.    float x = Limit.xmax;
  918.    float y = Limit.ymax;
  919.    float scale = (YScale(Limit.ymax) - YScale(Limit.ymin)) * ( 1 - cos45 ) 
  920.                  / (maxBin - minBin);
  921.    int i,j;
  922.    int xx = XScale(Limit.xmax);
  923.    int yy = YScale(Limit.ymax);
  924.    int ww, hh, oo, xxx, yyy;
  925.    XPoint points[5];
  926.  
  927.    static XColor bright, medium, dark;
  928.    static int GotColors = 0;
  929.    static Pixmap Medium;
  930.    static int GotPixmap = 0;
  931.    GC bright_gc, medium_gc, dark_gc;
  932.  
  933.    bright_gc = XCreateGC(h_display,h_drawable,0,NULL);
  934.    medium_gc = XCreateGC(h_display,h_drawable,0,NULL);
  935.    dark_gc   = XCreateGC(h_display,h_drawable,0,NULL);
  936.  
  937.    if (h_color && GotColors++ == 0)
  938.      {
  939.        Colormap Map = DefaultColormapOfScreen(h_screen);
  940.        bright.red   = 55000;
  941.        bright.blue  = 55000;
  942.        bright.green = 55000;
  943.        if (!XAllocColor(h_display,Map,&bright)) ColorError();
  944.  
  945.        medium.red   = 35000;
  946.        medium.blue  = 35000;
  947.        medium.green = 35000;
  948.        if (!XAllocColor(h_display,Map,&medium)) ColorError();
  949.  
  950.        dark.red   = 10000;
  951.        dark.blue  = 10000;
  952.        dark.green = 10000;
  953.        if (!XAllocColor(h_display,Map,&dark)) ColorError();
  954.  
  955.      }
  956.    else if (!h_color && GotPixmap++ == 0)
  957.      {
  958.        static char medium_data[] = {0x02, 0x01};
  959.        Medium = XCreatePixmapFromBitmapData(h_display,h_drawable,
  960.                         medium_data,2,2,0,1,1);
  961.      } 
  962.    if (h_color)
  963.      {
  964.        XSetForeground(h_display,medium_gc,medium.pixel);
  965.        XSetForeground(h_display,bright_gc,bright.pixel);
  966.        XSetForeground(h_display,dark_gc  ,dark.pixel);
  967.      }
  968.    else
  969.      {
  970.        XSetFillStyle(h_display,medium_gc,FillOpaqueStippled);
  971.        XSetStipple(h_display,medium_gc,Medium);
  972.  
  973.        XSetForeground(h_display,bright_gc,WhitePixelOfScreen(h_screen));
  974.        XSetForeground(h_display,medium_gc,WhitePixelOfScreen(h_screen));
  975.        XSetForeground(h_display,dark_gc  ,BlackPixelOfScreen(h_screen));
  976.        XSetBackground(h_display,medium_gc,BlackPixelOfScreen(h_screen));
  977.      }
  978.  
  979.    points[0].x = xx - (YScale(Limit.ymin) - YScale(Limit.ymax))*cos45;
  980.    points[0].y = yy + (YScale(Limit.ymin) - YScale(Limit.ymax))*(1-sin45);
  981.    points[1].x = XScale(Limit.xmin) - (YScale(Limit.ymin) - 
  982.                        YScale(Limit.ymax))*cos45;
  983.    points[1].y = yy + (YScale(Limit.ymin) - YScale(Limit.ymax))*(1-sin45);
  984.    points[2].x = XScale(Limit.xmin);
  985.    points[2].y = YScale(Limit.ymin);
  986.    points[3].x = xx;
  987.    points[3].y = YScale(Limit.ymin);
  988.    points[4].x = xx - (YScale(Limit.ymin) - YScale(Limit.ymax))*cos45;
  989.    points[4].y = yy + (YScale(Limit.ymin) - YScale(Limit.ymax))*(1-sin45);
  990.    XFillPolygon(h_display,h_drawable,medium_gc,points,5,
  991.         Convex,CoordModeOrigin);
  992.  
  993.    xxx = -(YScale(Limit.ymin) - YScale(Limit.ymax))*cos45;
  994.    yyy = (YScale(Limit.ymin) - YScale(Limit.ymax))*(1-sin45);
  995.  
  996.    for (j=0; j<nYBins; j++)
  997.      {
  998.        y -= yBinWidth;
  999.        hh = cos45*(YScale(y) - yy);
  1000.        oo = sin45*(yy - YScale(y));
  1001.  
  1002.        yy += hh;
  1003.        bins += nXBins*nYBins - 1;
  1004.       
  1005.        for (i=0; i<nXBins; i++)
  1006.          {
  1007.            int size = scale * (*bins - minBin);
  1008.            bins -= nYBins;
  1009.  
  1010.            x -= xBinWidth;
  1011.            ww = xx - XScale(x);
  1012.  
  1013.            xx -= ww;
  1014.  
  1015.            if (size == 0) continue;
  1016.  
  1017.            points[0].x = xx + xxx;
  1018.            points[0].y = yy + yyy + size;
  1019.            points[1].x = xx + xxx + ww;
  1020.            points[1].y = yy + yyy + size;
  1021.            points[2].x = xx + xxx + ww + oo;
  1022.            points[2].y = yy + yyy - hh + size;
  1023.            points[3].x = xx + xxx + oo;
  1024.            points[3].y = yy + yyy - hh + size;
  1025.            points[4].x = xx + xxx;
  1026.            points[4].y = yy + yyy + size;
  1027.            XFillPolygon(h_display,h_drawable,medium_gc,points,5,
  1028.             Convex,CoordModeOrigin);
  1029.  
  1030.            points[0].x = xx + xxx;
  1031.            points[0].y = yy + yyy;
  1032.            points[1].x = xx + xxx;
  1033.            points[1].y = yy + yyy + size;
  1034.            points[2].x = xx + xxx + oo;
  1035.            points[2].y = yy + yyy - hh + size;
  1036.            points[3].x = xx + xxx + oo;
  1037.            points[3].y = yy + yyy - hh;
  1038.            points[4].x = xx + xxx;
  1039.            points[4].y = yy + yyy;
  1040.            XFillPolygon(h_display,h_drawable,bright_gc,points,5,
  1041.             Convex,CoordModeOrigin);
  1042.  
  1043.            points[0].x = xx + xxx;
  1044.            points[0].y = yy + yyy;
  1045.            points[1].x = xx + xxx + ww;
  1046.            points[1].y = yy + yyy;
  1047.            points[2].x = xx + xxx + ww;
  1048.            points[2].y = yy + yyy + size;
  1049.            points[3].x = xx + xxx;
  1050.            points[3].y = yy + yyy + size;
  1051.            points[4].x = xx + xxx;
  1052.            points[4].y = yy + yyy;
  1053.            XFillPolygon(h_display,h_drawable,dark_gc,points,5,
  1054.             Convex,CoordModeOrigin);
  1055.          }
  1056.  
  1057.        xxx -= oo;
  1058.        xx = XScale(Limit.xmax);
  1059.        x = Limit.xmax;
  1060.      }           
  1061.  
  1062.    XFreeGC(h_display,bright_gc);
  1063.    XFreeGC(h_display,dark_gc);
  1064.    XFreeGC(h_display,medium_gc);
  1065. }
  1066.